export function debounce<T extends unknown[]>(
  fn: (...args: T) => void,
  delay: number,
) {
  let timeoutId: NodeJS.Timeout;

  return (...args: T) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => {
      fn(...args);
    }, delay);
  };
}

export function wrapInParenthesis(text: string) {
  let wrappedText = text;

  if (!text.startsWith('(')) wrappedText = `(${wrappedText}`;
  if (!text.endsWith(')')) wrappedText = `${wrappedText})`;

  return wrappedText;
}

export function downloadFile(filename: string, blob: Blob | string) {
  const isString = typeof blob === 'string';
  const objectURL = isString ? blob : URL.createObjectURL(blob);

  const anchorEl = document.createElement('a');
  anchorEl.href = objectURL;
  anchorEl.download = filename;

  document.body.appendChild(anchorEl);

  anchorEl.click();
  anchorEl.remove();

  if (!isString) URL.revokeObjectURL(objectURL);
}

export function parseURL(url: string) {
  try {
    return new URL(url);
  } catch (error) {
    return null;
  }
}

export function copyToClipboard(text: string) {
  return navigator.clipboard.writeText(text);
}

export function parseJSON<T = unknown, K = unknown>(
  input: string,
  def?: K,
): T | K {
  try {
    return JSON.parse(input) as T;
  } catch (_error) {
    return def as K;
  }
}

export function isObject<T>(input: T) {
  return typeof input === 'object' && !Array.isArray(input);
}

export function setItem(key: string, value: unknown) {
  return new Promise<void>((resolve, reject) => {
    const data: Record<string, unknown> = {};
    data[key] = value;
    chrome.storage.local.set(data, () => {
      if (chrome.runtime.lastError) {
        reject(chrome.runtime.lastError);
      } else {
        resolve();
      }
    });
  });
}

export function getItem(key: string) {
  return new Promise((resolve, reject) => {
    chrome.storage.local.get(key, (result) => {
      if (chrome.runtime.lastError) {
        reject(chrome.runtime.lastError);
      } else {
        resolve(result[key] || null);
      }
    });
  });
}

export function removeItem(key: string): Promise<void> {
  return new Promise((resolve, reject) => {
    chrome.storage.local.remove(key, () => {
      if (chrome.runtime.lastError) {
        reject(chrome.runtime.lastError);
      } else {
        resolve();
      }
    });
  });
}


// 获取IP相关信息的封装方法
export const getIPInfo = async () => {
  try {
    // 发送请求获取 IP 信息
    const response = await fetch(
      'https://check.myclientip.com/sys/config/ip/get-visitor-ip?type=ip2location',
      {
        headers: {
          accept:
            'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
          'accept-language': 'tr',
          'cache-control': 'max-age=0',
          priority: 'u=0, i',
          'sec-ch-ua':
            '"Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99"',
          'sec-ch-ua-mobile': '?0',
          'sec-ch-ua-platform': '"Windows"',
          'sec-fetch-dest': 'document',
          'sec-fetch-mode': 'navigate',
          'sec-fetch-site': 'none',
          'sec-fetch-user': '?1',
          'upgrade-insecure-requests': '1',
        },
        referrerPolicy: 'strict-origin-when-cross-origin',
        body: null,
        method: 'GET',
        mode: 'cors',
        credentials: 'omit',
      },
    );

    // 判断是否响应成功
    if (!response.ok) {
      throw new Error('Failed to fetch IP info');
    }

    // 获取 JSON 数据
    const data = await response.json();

    // 返回获取到的IP相关信息
    return data;
  } catch (error) {
    console.error('Error fetching IP information:', error);
    return null;
  }
};

export function generateUUID() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
    /[xy]/g,
    (c: string) => {
      const r = (Math.random() * 16) | 0;
      const v = c === 'x' ? r : (r & 0x3) | 0x8;
      return v.toString(16);
    },
  );
}

interface TypingOptions {
  minSpeed?: number;
  maxSpeed?: number;
  errorRate?: number;
  pauseAfterPunctuation?: boolean;
  simulateClick?: boolean;
  smartTypos?: boolean;
  deleteDelay?: number;
  simulateKeyEvents?: boolean; // 新增：是否模拟 keydown/keyup
}

export function simulateTyping(
  inputBox: HTMLInputElement | HTMLTextAreaElement,
  text: string,
  options: TypingOptions = {}
) {
  const {
    minSpeed = 30,
    maxSpeed = 150,
    errorRate = 0.1,
    pauseAfterPunctuation = true,
    simulateClick = true,
    smartTypos = true,
    deleteDelay = 350,
    simulateKeyEvents = true, // 默认不开启，防止性能问题
  } = options;

  let i = 0;
  let stopped = false;
  let typingTimer: number | null = null;

  const keyboardAdjacentMap: Record<string, string[]> = {
    a: ['s', 'q', 'z'], b: ['v', 'n', 'g'], c: ['x', 'v'], d: ['s', 'f', 'e'],
    e: ['w', 'r', 'd'], f: ['d', 'g', 'r'], g: ['f', 'h', 't'], h: ['g', 'j', 'y'],
    i: ['u', 'o', 'k'], j: ['h', 'k', 'u'], k: ['j', 'l', 'i'], l: ['k', 'o'],
    m: ['n', 'j'], n: ['b', 'm', 'h'], o: ['i', 'p', 'l'], p: ['o'],
    q: ['w', 'a'], r: ['e', 't', 'f'], s: ['a', 'd', 'w'], t: ['r', 'y', 'g'],
    u: ['y', 'i', 'j'], v: ['c', 'b'], w: ['q', 'e', 's'], x: ['z', 'c'],
    y: ['t', 'u', 'h'], z: ['x'],
  };

  function getSmartTypo(char: string): string {
    const lower = char.toLowerCase();
    const choices = keyboardAdjacentMap[lower];
    if (!choices || choices.length === 0) return char;
    const typo = choices[Math.floor(Math.random() * choices.length)];
    return char === lower ? typo : typo.toUpperCase();
  }

  function dispatchInput() {
    inputBox.dispatchEvent(new Event('input', { bubbles: true }));
  }

  // 合并 keydown 和 keyup 事件
  function dispatchKeyEvents(char: string) {
    const eventInit: KeyboardEventInit = {
      key: char,
      code: `Key${char.toUpperCase()}`,
      bubbles: true,
    };

    // 先触发 keydown，再触发 keyup，模拟按下和松开
    inputBox.dispatchEvent(new KeyboardEvent('keydown', eventInit));
    inputBox.dispatchEvent(new KeyboardEvent('keyup', eventInit));
  }

  function typeNextChar() {
    if (stopped || i >= text.length) return;

    const originalChar = text.charAt(i);
    let delay = Math.floor(Math.random() * (maxSpeed - minSpeed + 1)) + minSpeed;

    if (pauseAfterPunctuation && /[.,!?;:]/.test(originalChar)) {
      delay += Math.floor(Math.random() * 200) + 100;
    }

    const shouldMakeTypo = Math.random() < errorRate;
    const useTypo = shouldMakeTypo && smartTypos;
    const wrongChar = useTypo ? getSmartTypo(originalChar) : originalChar;

    if (simulateKeyEvents) dispatchKeyEvents(wrongChar); // 触发键盘事件

    inputBox.value += wrongChar;
    dispatchInput();

    typingTimer = window.setTimeout(() => {
      if (shouldMakeTypo) {
        inputBox.value = inputBox.value.slice(0, -1);
        dispatchInput();

        typingTimer = window.setTimeout(() => {
          if (simulateKeyEvents) dispatchKeyEvents(originalChar);
          inputBox.value += originalChar;
          dispatchInput();
          i++;
          typingTimer = window.setTimeout(typeNextChar, delay);
        }, deleteDelay);
      } else {
        i++;
        typingTimer = window.setTimeout(typeNextChar, delay);
      }
    }, delay);
  }

  if (simulateClick) {
    const clickEvent = new MouseEvent("click", { bubbles: true });
    inputBox.dispatchEvent(clickEvent);
  }

  inputBox.focus();
  typeNextChar();

  return {
    stop() {
      stopped = true;
      if (typingTimer !== null) clearTimeout(typingTimer);
    },
  };
}


/**
 * 随机选择并选中指定容器内的单选按钮
 * @param containerSelector - 可选的CSS选择器，用于指定包含单选按钮的容器。默认为'tr'或'ul'。
 * @returns 无返回值
 */
export function selectRandomRadios(containerSelector: string = 'tr') {
  let containers: any = [];
  if (!containerSelector) {
    containerSelector = 'tr';
  }
  // 获取所有符合选择器的容器元素
  containers = document.querySelectorAll(containerSelector);
  // 如果没有找到'tr'元素，则尝试使用'ul'作为选择器
  if (containers.length === 0) {
    containerSelector = 'ul';
    containers = document.querySelectorAll(containerSelector);
  }

  // 遍历每个容器
  containers.forEach((container: Element) => {
    // 在当前容器中查找所有的单选按钮
    const radios: NodeListOf<HTMLInputElement> = container.querySelectorAll(
      'input[type="radio"]',
    );

    // 如果这一容器中有单选按钮
    if (radios.length > 0) {
      // 随机选择一个单选按钮
      const randomIndex = Math.floor(Math.random() * radios.length);
      // 设置选中的单选按钮为选中状态
      radios[randomIndex].checked = true;
      // 触发单选按钮的change事件，以确保相关的事件监听器能够响应
      const event = new Event('change', { bubbles: true });
      radios[randomIndex].dispatchEvent(event);
    }
  });
}
export function selectRandomCheckboxes(containerSelector: string = 'tr') {
  let containers: any = [];
  if (!containerSelector) {
    containerSelector = 'tr';
  }

  // 获取所有符合选择器的容器元素
  containers = document.querySelectorAll(containerSelector);

  // 如果没有找到 'tr' 元素，则尝试使用 'ul' 作为选择器
  if (containers.length === 0) {
    containerSelector = 'ul';
    containers = document.querySelectorAll(containerSelector);
  }

  // 遍历每个容器
  containers.forEach((container: Element) => {
    // 在当前容器中查找所有的复选框
    const checkboxes: NodeListOf<HTMLInputElement> = container.querySelectorAll(
      'input[type="checkbox"]',
    );

    // 如果这一容器中有复选框
    if (checkboxes.length > 0) {
      // 随机选择 2 个复选框
      const randomIndexes = new Set<number>();

      // 确保选择 2 个不同的复选框
      while (randomIndexes.size < Math.min(2, checkboxes.length)) {
        const randomIndex = Math.floor(Math.random() * checkboxes.length);
        randomIndexes.add(randomIndex);
      }

      // 将选中的复选框设置为选中状态
      randomIndexes.forEach((index) => {
        checkboxes[index].checked = true;
        // 触发复选框的 change 事件，以确保相关的事件监听器能够响应
        const event = new Event('change', { bubbles: true });
        checkboxes[index].dispatchEvent(event);
      });
    }
  });
}

export async function getTextFromClipboard() {
  try {
    const clipboardText = await navigator.clipboard.readText();
    console.log('clipboardText: ', clipboardText);
    return clipboardText;
  } catch (error) {
    console.log('无法读取剪切板内容:', error);
    return '';
  }
}

export function startTyping(text?: string) {
  const inputBox = document.activeElement as HTMLTextAreaElement;
  if (
    inputBox &&
    (inputBox.tagName === 'INPUT' || inputBox.tagName === 'TEXTAREA')
  ) {
    inputBox.focus();
    if (text && text.length) {
      // 如果传入了文本，直接用
      simulateTyping(inputBox, text);
    } else {
      // 否则从剪切板拿文本
      getTextFromClipboard().then((clipboardText) => {
        console.log('clipboardText: ', clipboardText);
        if (clipboardText && clipboardText.length) {
          simulateTyping(inputBox, clipboardText);
        }
      });
    }
  }
}

// 解除所有 user-select 限制
export function enableTextSelection() {
  const style = document.createElement('style');
  style.innerHTML = `
      * {
          user-select: text !important;
          -webkit-user-select: text !important;
          -moz-user-select: text !important;
          -ms-user-select: text !important;
      }
  `;
  document.head.appendChild(style);

  // 遍历所有元素，移除 inline style 中的 user-select: none
  document.querySelectorAll('*').forEach((el: any) => {
    if (el.style.userSelect === 'none') {
      el.style.userSelect = 'text';
    }
  });

  console.log('Text selection enabled on this page.');
}

export function isOnlineImageUrl(url: string) {
  // 定义正则表达式来匹配图片 URL
  const imageUrlRegex = /^https?:\/\/.*\.(jpg|jpeg|png|gif|webp)$/i;

  // 检查字符串是否符合图片 URL 的基本格式
  if (!imageUrlRegex.test(url)) {
    return false;
  }
  return true;
}


export function isRRWebDetected() {
 // @ts-ignore
  return !!(window.rrweb || window.rrwebRecord || window.rrwebReplay);
}


export const innReqParams:any = {
  "headers": {
    "accept": "application/json, text/plain, */*",
    "accept-language": "en-AU,en-GB;q=0.9,en;q=0.8",
    "cache-control": "max-age=0",
    "content-type": "application/json",
    "if-none-match": "W/\"785-oc3q3fFb4BUv1D6XtKd3HbEl0Sk\"",
    "priority": "u=1, i",
    "sec-ch-ua": "\"Chromium\";v=\"134\", \"Not:A-Brand\";v=\"24\", \"Google Chrome\";v=\"134\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "sec-fetch-dest": "empty",
    "sec-fetch-mode": "cors",
    "Origin": "https://edgesurvey.innovatemr.net",
    "sec-fetch-site": "same-site"
  },
  "referrer": "https://edgesurvey.innovatemr.net/",
  "referrerPolicy": "strict-origin-when-cross-origin",
  "body": null,
  "method": "GET",
  "mode": "cors",
  "credentials": "omit"
}
